package org.oslims.client.presenter;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.oslims.client.AsyncCall;
import org.oslims.client.MainEventBus;
import org.oslims.client.service.AnalysisResultServiceAsync;
import org.oslims.client.service.RequestServiceAsync;
import org.oslims.client.service.SampleServiceAsync;
import org.oslims.client.uicomponents.LabeledCheckBox;
import org.oslims.client.uicomponents.ParameterResultCell;
import org.oslims.client.uicomponents.TagTreeItem;
import org.oslims.client.uicomponents.WidgetUtils;
import org.oslims.client.view.impl.ShowResultsViewImpl;
import org.oslims.domain.AbstractSample;
import org.oslims.domain.AnalysisResult;
import org.oslims.domain.ParameterResult;
import org.oslims.domain.Request;

import com.google.gwt.event.logical.shared.OpenEvent;
import com.google.gwt.event.logical.shared.OpenHandler;
import com.google.gwt.i18n.client.DateTimeFormat;
import com.google.gwt.user.cellview.client.CellTable;
import com.google.gwt.user.cellview.client.Column;
import com.google.gwt.user.cellview.client.TextColumn;
import com.google.gwt.user.client.ui.DockLayoutPanel;
import com.google.gwt.user.client.ui.TreeItem;
import com.mvp4g.client.annotation.InjectService;
import com.mvp4g.client.annotation.Presenter;
import com.mvp4g.client.presenter.BasePresenter;

@Presenter(view = ShowResultsViewImpl.class)
public class ShowResultsPresenter extends BasePresenter<ShowResultsViewImpl, MainEventBus> {

	private AnalysisResultServiceAsync analysisResultService;
	private SampleServiceAsync sampleService;
	private RequestServiceAsync requestService;

	public ShowResultsPresenter() {

	}

	public void onShowResults(DockLayoutPanel mainWidget) {
		WidgetUtils.removeCenterWidget(mainWidget);
		mainWidget.add(view.getViewWidget());

		refreshView();
	}

	public void bind() {

		view.getRequestTree().addOpenHandler(new OpenHandler<TreeItem>() {

			@Override
			public void onOpen(OpenEvent<TreeItem> arg0) {
				final TagTreeItem ti = (TagTreeItem) arg0.getTarget();

				loadDataForItem(ti);
			}

		});
	}

	private void loadDataForItem(final TagTreeItem ti) {
		if (ti.getTag() instanceof AbstractSample) {
			getAnalysisResultsForSample(ti);
		} else if (ti.getTag() instanceof Request) {
			getSamplesForRequest(ti);
		}
	}

	private void getSamplesForRequest(final TagTreeItem ti) {

		sampleService.getAllSamplesByRequest((Request) ti.getTag(), new AsyncCall<List<AbstractSample>>() {

			@Override
			protected void onFailureE(Throwable caught) {
				eventBus.error(caught.getMessage());
			}

			@Override
			protected void onSuccessE(List<AbstractSample> result) {
				ti.removeItems();

				for (AbstractSample as : result) {
					TagTreeItem tiSample = new TagTreeItem();
					tiSample.setTag(as);

					final LabeledCheckBox sampleSelectionBox = new LabeledCheckBox();
					sampleSelectionBox.setTag(as);
					sampleSelectionBox.setText(as.getCode());

					tiSample.setWidget(sampleSelectionBox);

					ti.addItem(tiSample);
					tiSample.addItem("...");
				}
			}
		});
	}

	private void getAnalysisResultsForSample(final TagTreeItem ti) {

		analysisResultService.getAnalysisResultsBySampleAndState((AbstractSample) ti.getTag(), "%", new AsyncCall<List<AnalysisResult>>() {

			@Override
			protected void onFailureE(Throwable caught) {
				eventBus.error(caught.getMessage());
			}

			@Override
			protected void onSuccessE(List<AnalysisResult> result) {
				ti.removeItems();

				AbstractSample sample = (AbstractSample) ti.getTag();
				List<AbstractSample> sampleList = new ArrayList<AbstractSample>();
				sampleList.add(sample);

				final CellTable<AbstractSample> sampleInformationTable = new CellTable<AbstractSample>(1);

				sampleInformationTable.addColumn(new TextColumn<AbstractSample>() {

					@Override
					public String getValue(AbstractSample object) {
						return object.getOrigin();
					}
				}, "Origin");

				sampleInformationTable.addColumn(new TextColumn<AbstractSample>() {

					@Override
					public String getValue(AbstractSample object) {
						return object.getDescription();
					}
				}, "Description");

				sampleInformationTable.addColumn(new TextColumn<AbstractSample>() {

					@Override
					public String getValue(AbstractSample object) {
						return object.getSampleType().getName();
					}
				}, "Sample Type");

				sampleInformationTable.addColumn(new TextColumn<AbstractSample>() {

					@Override
					public String getValue(AbstractSample object) {
						return object.getState();
					}
				}, "State");

				sampleInformationTable.setData(0, 1, sampleList);

				ti.addItem(sampleInformationTable);

				for (AnalysisResult ar : result) {

					TreeItem tiAnalysisName = new TreeItem();

					final LabeledCheckBox analysisSelection = new LabeledCheckBox();

					analysisSelection.setText(ar.getAnalysis().getName());
					analysisSelection.setLabelStyleName("analysisNameTreeItem");
					analysisSelection.setTag(ar);

					tiAnalysisName.setWidget(analysisSelection);

					ti.addItem(tiAnalysisName);

					final CellTable<ParameterResult> table = new CellTable<ParameterResult>(ar.getParameterResults().size());

					table.addColumn(new TextColumn<ParameterResult>() {

						@Override
						public String getValue(ParameterResult object) {
							return object.getParameter().getName();
						}
					}, "Parameter");

					table.addColumn(new TextColumn<ParameterResult>() {

						@Override
						public String getValue(ParameterResult object) {
							return object.getState();
						}
					}, "State");

					table.addColumn(new TextColumn<ParameterResult>() {

						@Override
						public String getValue(ParameterResult object) {
							if (object.getMeasuredAt() != null) {
								return DateTimeFormat.getShortDateTimeFormat().format(object.getMeasuredAt());
							}
							return "";
						}
					}, "Meas. Time");

					Column<ParameterResult, ParameterResult> resultCol = new Column<ParameterResult, ParameterResult>(new ParameterResultCell(false)) {

						@Override
						public ParameterResult getValue(ParameterResult object) {
							if (object.getMeasuredAt() == null)
								object.setMeasuredAt(new Date());
							return object;
						}
					};

					table.addColumn(resultCol, "Result");

					table.setPageSize(ar.getParameterResults().size());
					table.setData(0, ar.getParameterResults().size(), ar.getParameterResults());

					ti.addItem(table);
				}
			}
		});
	}

	public void refreshView() {

		view.getRequestTree().clear();

		requestService.getRequestByState("%", new AsyncCall<List<Request>>() {

			@Override
			protected void onFailureE(Throwable caught) {
				eventBus.error(caught.getMessage());
			}

			@Override
			protected void onSuccessE(List<Request> result) {
				view.getRequestTree().clear();

				for (Request r : result) {
					TagTreeItem ti = new TagTreeItem();
					ti.setTag(r);
					ti.setText(r.getCode());
					view.getRequestTree().addItem(ti);
					ti.addItem("...");

				}
			}
		});
	}

	@InjectService
	public void setAnalysisResultService(AnalysisResultServiceAsync analysisResultService) {
		this.analysisResultService = analysisResultService;
	}

	@InjectService
	public void setSampleService(SampleServiceAsync sampleService) {
		this.sampleService = sampleService;
	}

	@InjectService
	public void setRequestService(RequestServiceAsync requestService) {
		this.requestService = requestService;
	}

}
